package com.google.code.gronono.gps.ui;

import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.text.MessageFormat;

import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

import org.apache.commons.lang.SystemUtils;
import org.apache.log4j.Logger;

import com.google.code.gronono.commons.i18n.BundleKey;
import com.google.code.gronono.commons.i18n.BundleName;
import com.google.code.gronono.commons.i18n.I18N;
import com.google.code.gronono.commons.swing.JOptionPaneExceptionHandler;
import com.google.code.gronono.commons.swing.SwingUtils;
import com.google.code.gronono.gps.model.Configuration;
import com.google.code.gronono.gps.ui.controller.GPSController;

/**
 * Interface graphique de GPS.
 *
 * @author Arnaud BRUNET
 */
@BundleName(value = "com.google.code.gronono.gps.gui")
public class GPSGui {
	/** Logger. */
	private static final Logger logger = Logger.getLogger(GPSGui.class);

	/** Message de démarrage de l'application. */
	@BundleKey(value = "gps.start.msg")
	private static String APP_START_MSG;
	/** Titre de l'application. */
	@BundleKey(value = "gps.app.name")
	private static String APP_NAME;
	/** Titre de l'application. */
	@BundleKey(value = "gps.fatal.err.msg")
	private static String FATAL_ERR_MSG;
	/** Version minimale la JVM requise. */
	@BundleKey("gps.jvm.min.version")
	private static int JVM_MIN_VERSION;
	/** Titre du message d'erreur lorsque la version de la JVM n'est pas la bonne. */
	@BundleKey("gps.jvm.version.err.title")
	private static String JVM_VERSION_ERROR_TITLE;
	/** Message d'erreur lorsque la version de la JVM n'est pas la bonne. */
	@BundleKey("gps.jvm.version.err.msg")
	private static String JVM_VERSION_ERROR_MSG;

	/** Nom du package de base de l'application. */
	private static final String PACKAGE = "com/google/code/gronono";

	/**
	 * Lance la fenêtre principale.
	 * @param args Les arguments. Pas utilisé.
	 */
	public static void main(final String[] args) {
		logger.debug("main");
		// Pour calculer le temps de chargement de l'application
		long t = 0;
		if (logger.isDebugEnabled()) {
			t = System.currentTimeMillis();
		}

		// Sélection du Look And Feel
		SwingUtils.setSystemLookAndFeel();

		// Initialisation des ressources I18N
		I18N.initializePackage(PACKAGE);

		logger.info(MessageFormat.format(APP_START_MSG, APP_NAME));

		// Validation du JRE
		if (!SystemUtils.isJavaVersionAtLeast(JVM_MIN_VERSION)) {
			final String msg = MessageFormat.format(JVM_VERSION_ERROR_MSG, JVM_MIN_VERSION);
			logger.error(msg);
			JOptionPane.showMessageDialog(null, msg, JVM_VERSION_ERROR_TITLE, JOptionPane.ERROR_MESSAGE);
			System.exit(-1);
		}

		// Enregistrement du gestionnaire d'exceptions non catchées
		Thread.setDefaultUncaughtExceptionHandler(new JOptionPaneExceptionHandler());

		try {
			// Chargement de la configuration
			final Configuration configuration = Configuration.load(false);

			// Lancement asynchrone
			SwingUtilities.invokeLater(new Runnable() {
				public void run() {
					// Initialisation des composants
					final GPSController controller = new GPSController(configuration);
					final JFrame gpsFrame = controller.getGPSFrame();

					// Gestion de la fermeture de fenêtre
					gpsFrame.addWindowListener(new WindowAdapter() {
						@Override
						public void windowClosing(final WindowEvent e) {
							controller.quit();
						}
					});

					// La touche ESCAPE permet de quitter l'application
					final JComponent rootPane = gpsFrame.getRootPane();
					final Action quitAction = controller.getQuitAction();
					final InputMap inputMap = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
					final ActionMap actionMap = rootPane.getActionMap();
					inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), quitAction);
					actionMap.put(quitAction, quitAction);

					// Ok --> rendre la fenêtre principale visible
					gpsFrame.setVisible(true);
				}
			});
		} catch (final IOException e) {
			final StringBuilder msg = new StringBuilder("IOException : ").append(e.getMessage());
			if (e.getCause() != null) msg.append(e.getCause());
			logger.error(msg.toString(), e);
			JOptionPane.showMessageDialog(null, msg.toString(), e.getClass().getName(), JOptionPane.ERROR_MESSAGE);
		} catch (final Throwable ex) {
			final StringBuilder msg = new StringBuilder(MessageFormat.format(FATAL_ERR_MSG, ex.getMessage()));
			if (ex.getCause() != null) msg.append(ex.getCause());
			logger.error(msg.toString(), ex);
			JOptionPane.showMessageDialog(null, msg.toString(), ex.getClass().getName(), JOptionPane.ERROR_MESSAGE);
		}

		// Debug : afficher le temps de chargement de l'application
		if (logger.isDebugEnabled()) {
			logger.debug("App loaded in : " + (System.currentTimeMillis() - t) + " ms");
		}
	}
}
